﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using QuanserClient;

namespace TankController.Dominio
{
    public abstract class AbstractControlador : IControlador
    {
        //protected const double LIMITE_SEGURANCA = 0.9;
        protected const double TENSAO_DESLIGAMENTO = 0;

        protected IPlanta planta;
        protected ISinal sinalSaida = new Sinal("Saída", TipoSinal.Saida);
        protected ISinal sinalProcessoSensor1 = new Sinal("Nível Tanque 1", TipoSinal.Nivel);
        protected ISinal sinalProcessoSensor2 = new Sinal("Nível Tanque 2", TipoSinal.Nivel);
        protected int tempoAtual;
        protected int periodo;
        protected Timer temporizador;
        //protected Boolean isAtivo;
        protected double limiteSeguranca;

        private void IncrementarTempo()
        {
            tempoAtual++;
        }

        public void Iniciar()
        {
            Reiniciar();

            if (Global.TipoConfiguracao == TipoConfiguracao.ConfiguracaoA || Global.TipoConfiguracao == TipoConfiguracao.ConfiguracaoC)
            {
                sinalProcessoSensor1.Tipo = TipoSinal.Resposta;
                sinalProcessoSensor2.Tipo = TipoSinal.Nivel;
            }
            else
            {
                sinalProcessoSensor1.Tipo = TipoSinal.Nivel;
                sinalProcessoSensor2.Tipo = TipoSinal.Resposta;
            }

            temporizador = new Timer(Executar, null, 0, periodo);
        }

        protected void Executar(Object stateInfo)
        {
            try
            {
                lock (Global.MonitorSinais)
                {
                    DateTime comeco = DateTime.Now;
                    DateTime fim;

                    if (Global.Status == Status.Play)
                    {
                        Controlar();

                        IncrementarTempo();
                    }
                    else
                    {
                        temporizador.Change(Timeout.Infinite, Timeout.Infinite);
                        temporizador.Dispose();

                        temporizador = null;

                        tempoAtual = 0;

                        //lock (Global.MonitorSinais)
                        //{
                        foreach (Sinal sinal in GetSinais())
                        {
                            sinal.PontoList.Clear();
                        }
                        //}

                        planta.Escrever(TENSAO_DESLIGAMENTO);
                    }

                    fim = DateTime.Now;

                    Console.WriteLine("Iteração: " + tempoAtual + ". Tempo total de execução do controlador: " + (fim - comeco).TotalMilliseconds);
                }
            }
            catch (QuanserClientException qcex)
            {
                //TODO: Tratar exceção
            }
            catch (Exception ex)
            {
                
            }
        }

        public IList<ISinal> GetSinais()
        {
            return GetSinaisAltura().Concat(GetSinaisTensao()).ToList();
        }

        protected abstract void Controlar();
        public abstract IList<ISinal> GetSinaisAltura();
        public abstract IList<ISinal> GetSinaisTensao();
        protected abstract void Reiniciar();

        protected double ManterNivelSeguranca(double valorProcesso, double valorSaida)
        {
            if (valorProcesso >= planta.LimiteAlturaPlantaHigh * (1 - limiteSeguranca))// ||
            {
                return planta.LimiteTensaoPlantaLow;
            }
            else if (valorProcesso <= planta.LimiteAlturaPlantaLow + (planta.LimiteAlturaPlantaHigh * limiteSeguranca))// ||
            {
                if (valorSaida < TENSAO_DESLIGAMENTO)
                {
                    return planta.LimiteTensaoPlantaHigh;
                }
                else if (valorSaida > planta.LimiteTensaoPlantaHigh)
                {
                    return planta.LimiteTensaoPlantaHigh;
                }
                else
                {
                    return valorSaida;
                }
            }
            else
            {
                if (valorSaida < planta.LimiteTensaoPlantaLow)
                {
                    return planta.LimiteTensaoPlantaLow;
                }
                else if (valorSaida > planta.LimiteTensaoPlantaHigh)
                {
                    return planta.LimiteTensaoPlantaHigh;
                }
                else
                {
                    return valorSaida;
                }
            }
        }

        public IPlanta Planta
        {
            get { return planta; }
            set { planta = value; }
        }
        public ISinal SinalSaida
        {
            get { return sinalSaida; }
            set { sinalSaida = value; }
        }
        public ISinal SinalProcesso
        {
            get { return sinalProcessoSensor1; }
            set { sinalProcessoSensor1 = value; }
        }
        public abstract double Ganho
        {
            get;
            set;
        }
        public int Periodo
        {
            get { return periodo; }
            set { periodo = value; }
        }
        /*public Boolean IsAtivo
        {
            get { return isAtivo; }
        }*/
        public abstract String Descricao
        {
            get;
        }
        public double LimiteSeguranca
        {
            get { return limiteSeguranca; }
            set { limiteSeguranca = value; }
        }
    }
}
